`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2016/12/14 15:16:27
// Design Name: Chongyaoxu
// Module Name: top_SM3
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////AHB-Lite SM3 register address///////////////////////////
//SM3_base_addr=32'h50002xxx

`define SIZE_BYTE 3'b00
`define SIZE_HALF 3'b01
`define SIZE_WORD 3'b10
`define SM3_Reg_addr Reg_ofs_addr[11:6]			//register offset address
`define SM3_N Reg_ofs_addr[5:2]					//Number
`define SM3_Reg_addr_R HADDR[11:6]			//register offset address
`define SM3_N_R HADDR[5:2]					//Number

module top_SM3(
    input HRESETn,
    input HCLK,
    input HWRITE,
    input HSEL,
    input HMASTLOOK,
    input [2:0] HSIZE,HBURST,
    input [1:0] HTRANS,
    input [31:0] HADDR,
    input [31:0] HWDATA,
    input [3:0] HPROT,
    output HREADY,
    output HRESP,
    output [31:0] HRDATA
    );
    
 parameter
        addr_msg_in=6'h0,
        addr_control=12'h060, addr_status=12'h064;
    
    /////////////////////////AHB-Lite SM3 reg///////////////////////////////////////
    reg [31:0] msg_in [0:15]    ;                        //Define 16 word 32 bit register ,save x1
    reg [31:0] control_reg ;                        //control register
    reg [31:0] msg_out [0:7]  ;                        //Define 8 word 32 bit register ,save x3
wire [31:0] msg_out8,msg_out7,msg_out6,msg_out5,msg_out4,msg_out3,msg_out2,msg_out1;
always @(msg_out1 or msg_out2 or msg_out3 or msg_out4 or msg_out5 or msg_out6 or msg_out7 or msg_out8)
begin
	{msg_out[0],msg_out[1],msg_out[2],msg_out[3],msg_out[4],msg_out[5],msg_out[6],msg_out[7]} = {msg_out8,msg_out7,msg_out6,msg_out5,msg_out4,msg_out3,msg_out2,msg_out1};
end
    wire [31:0] status_reg;
    
    wire ahb_trans_valid;
    wire ahb_trans_clear;
    wire ahb_write_en;
    wire ahb_read_en;
    reg lite_write_req;
    reg lite_read_req;
    
    reg [31:0] rdata;
    
    reg [1:0]  HTRANS_reg;
    reg        HWRITE_reg,HSEL_reg;
    reg [11:0] Reg_ofs_addr_ff;
    wire [11:0] Reg_ofs_addr;
    reg [2:0]  HSIZE_reg;
    /*
    (* MARKDEBUG = "TRUE" *)reg [1:0]     HTRANS_reg;
    (* MARKDEBUG = "TRUE" *)reg         HWRITE_reg;
    (* MARKDEBUG = "TRUE" *)reg [11:0] SM2_ofs_addr;
    (* MARKDEBUG = "TRUE" *)wire HCLK;
    (* MARKDEBUG = "TRUE" *)wire [31:0] HADDR;
    (* MARKDEBUG = "TRUE" *)wire [31:0] HWDATA;*/
    
    assign HRDATA=rdata;
    assign HREADY= 1'b1;
    assign HRESP=  1'b0;
    
    assign ahb_trans_valid = HSEL && HREADY && 
                             (HTRANS[1] == 1'b1);
    assign ahb_write_en = ahb_trans_valid && HWRITE;
    assign ahb_read_en  = ahb_trans_valid && (!HWRITE);
    
    
//    assign ahb_trans_clear = hready && !hsel;
    //////////////////////////Write enable signal///////////////////////////////
    always @ (posedge HCLK or negedge HRESETn)
    begin
      if(!HRESETn)
      begin
        lite_write_req <= 1'b0;
      end
      else if (ahb_write_en)
      begin
        lite_write_req <= 1'b1;
      end
      else
      begin
        lite_write_req <= 1'b0;
      end 
    end
    /*
    //////////////////////////Read enable signal///////////////////////////////
    always @ (posedge HCLK or negedge HRESETn)
    begin
      if(!HRESETn)
      begin
        lite_read_req <= 1'b0;
      end
      else if (ahb_read_en)
      begin
        lite_read_req <= 1'b1;
      end
      else
      begin
        lite_read_req <= 1'b0;
      end 
    end    
    */
    ////////////////ADDR,TRANS,WRITE signal input//////////////////////
    always@(posedge HCLK or negedge HRESETn)
      begin 
        if(!HRESETn)
          begin 
            Reg_ofs_addr_ff  <=    12'hfff;
            HSIZE_reg   <=  3'b0;
          end
        else if(ahb_trans_valid)
          begin  
            Reg_ofs_addr_ff  <=    HADDR[11:0];
            HSIZE_reg   <=  HSIZE;
          end
        else
          begin  
            Reg_ofs_addr_ff  <=    12'hfff;
            HSIZE_reg   <=   3'b0;
          end        
      end
    assign   Reg_ofs_addr = Reg_ofs_addr_ff;
    //////////////////////control_reg input//////////////////////////////////
    always@(posedge HCLK or negedge HRESETn)  
      begin  
        if( !HRESETn)
            control_reg    <=    32'hffff_ffff;
        else if( (Reg_ofs_addr==addr_control)&&(lite_write_req == 1'b1)&&(HSIZE_reg == `SIZE_WORD) )
            control_reg    <=    HWDATA;
    //    else if( (status_reg[3:0] == 4'h2)&&(`SM2_Reg_addr==addr_x3)&&(!HWRITE_reg)&&(HTRANS_reg[1])&&(HSEL_reg)&&(HSIZE_reg == `SIZE_WORD) )        //Compute finish and read X3
    //        control_reg[4] <=    1;    //???
        else
            control_reg    <= control_reg;
      end  
      
    //////////////////////HWDATA input//////////////////////////////////////// 
    integer sm3_i;
    always@(posedge HCLK or negedge HRESETn)
    begin
        if(!HRESETn)  begin
            for(sm3_i = 0; sm3_i<16; sm3_i=sm3_i+1)begin
                msg_in[sm3_i] <=    32'h0;
            end
        end
		else if(control_reg[5]==1'b1) begin
            for(sm3_i = 0; sm3_i<16; sm3_i=sm3_i+1)begin
                msg_in[sm3_i] <=    32'h0;
            end
		end
		else if( (`SM3_Reg_addr==addr_msg_in)&&(lite_write_req == 1'b1)&&(HSIZE_reg == `SIZE_WORD) )begin
			msg_in[`SM3_N] <= HWDATA;
		end
        else begin
            for(sm3_i = 0; sm3_i<16; sm3_i=sm3_i+1)begin
                msg_in[sm3_i] <=msg_in[sm3_i];
            end
        end
    end
    
    //////////////////////HRDATA output//////////////////////////////////////// 
    always@(posedge HCLK or negedge HRESETn)
      begin
        if(!HRESETn)begin
            rdata<=32'hFFFF_FFFF;
        end
        else if( ahb_read_en && (HSIZE == `SIZE_WORD) )begin
            if(HADDR[11:0] == addr_control)
                rdata <= control_reg;
            else if(HADDR[11:0] == addr_status)
                rdata <= status_reg;
            else if(`SM3_Reg_addr_R == addr_msg_in)        //Read msg_in
                rdata <= msg_in[`SM3_N_R];
            else if(!HADDR[5])            //Read msg_out
                rdata <= msg_out[`SM3_N_R];
            else                               //Read invalid address,return 0xffff_ffff(-1) 
                rdata<=32'hFFFF_FFFF;
        end
        else
          rdata<=rdata;
      end
      
      
SM3_reg_ahb SM3_x( .clk(HCLK) , .rst(HRESETn) , .control(control_reg) ,.status(status_reg) ,
      .msg_in1(msg_in[0]) ,.msg_in2(msg_in[1])  ,.msg_in3(msg_in[2])  ,.msg_in4(msg_in[3])  ,.msg_in5(msg_in[4])  ,.msg_in6(msg_in[5])  ,.msg_in7(msg_in[6])  ,.msg_in8(msg_in[7])  ,
      .msg_in9(msg_in[8]) ,.msg_in10(msg_in[9]) ,.msg_in11(msg_in[10]) ,.msg_in12(msg_in[11]) ,.msg_in13(msg_in[12]) ,.msg_in14(msg_in[13]) ,.msg_in15(msg_in[14]) ,.msg_in16(msg_in[15]) , 
      .msg_out1(msg_out1),.msg_out2(msg_out2) ,.msg_out3(msg_out3) ,.msg_out4(msg_out4) ,.msg_out5(msg_out5) ,.msg_out6(msg_out6) ,.msg_out7(msg_out7) ,.msg_out8(msg_out8)  );
endmodule
